/*
 *所有关于Recycled_Material_Ingredient_Record类的业务代码应在此处编写
*可使用repository.调用常用方法，获取EF/Dapper等信息
*如果需要事务请使用repository.DbContextBeginTransaction
*也可使用DBServerProvider.手动获取数据库相关信息
*用户信息、权限、角色等使用UserContext.Current操作
*Recycled_Material_Ingredient_RecordService对增、删、改查、导入、导出、审核业务代码扩展参照ServiceFunFilter
*/
using DGZImp.Core.BaseProvider;
using DGZImp.Core.Extensions.AutofacManager;
using ATkg.BizAppProject.DomainModels;
using System.Linq;
using DGZImp.Core.Utilities;
using System.Linq.Expressions;
using DGZImp.Core.Extensions;

using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Http;
using ATkg.BizAppProject.IRepositories;
using DGZImp.Core.Exceptions;
using Newtonsoft.Json.Linq;
using static ATkg.BizAppProject.Controllers.Recycled_Material_Ingredient_RecordController;
using DocumentFormat.OpenXml.Office2010.Excel;
using System.DirectoryServices.ActiveDirectory;
using DGZImp.Core.DbSqlSugar;
using System.Text.RegularExpressions;

namespace ATkg.BizAppProject.Services
{
    public partial class Recycled_Material_Ingredient_RecordService
    {
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly IRecycled_Material_Ingredient_RecordRepository _repository;//访问数据库
        private readonly AmesSyncService _amesSyncService;


        [ActivatorUtilitiesConstructor]
        public Recycled_Material_Ingredient_RecordService(
            IRecycled_Material_Ingredient_RecordRepository dbRepository,
            IHttpContextAccessor httpContextAccessor,
            AmesSyncService amesSyncService
            )
        : base(dbRepository)
        {
            _httpContextAccessor = httpContextAccessor;
            _repository = dbRepository;
            //多租户会用到这init代码，其他情况可以不用
            //base.Init(dbRepository);
            _amesSyncService = amesSyncService;

        }

        public async Task<List<Recycled_Material_Ingredient_Record>> GetOutInfo()
        {

            var qDomain = new List<object>
            {
                "&", // AND 条件
                new List<object> { "state", "=", "done" },
                new List<object> { "picking_type_id", "=", 116 },
                new List<object> { "alloy_top_id", "ilike", "LPH7" },
                // new List<object> { "date_done", ">=", "2024-10-10 00:00:00" },
                new List<object> { "date_done", ">=", "2000-10-10 00:00:00" },
            };


            var qFields = new List<string> {
                "id",
                "alloy_top_id",
                "lot_ids_str",  
            };
            var qPage = new
            {
                limit = 10000,
                offset = 0,
                context = new { lang = "zh_CN", tz = "Asia/Shanghai" },
            };
            var resp = await _amesSyncService.CallSearchRead("stock.picking", qDomain, qFields, qPage);  //获取全部符合合金号和日期的信息

            if (resp.ContainsKey("error"))
            {
                var message = $"【拉取单据】{resp["error"].ToString()}";
                throw new AppException(message);
            }
            var res = (JArray)resp["result"];

            if (res == null || res.Count <= 0)
            {
                return null;
            }
            var r = new List<Recycled_Material_Ingredient_Record>();

            for (var i = 0; i < res.Count; i++)
            {
                var x = (JObject)res[i];
                var id = (int)x["id"];
                var AllyTopId = (string)x["alloy_top_id"][1];
                if (!string.IsNullOrEmpty(AllyTopId) && AllyTopId[AllyTopId.Length - 1] != 'R')
                {
                    AllyTopId += "R";
                }
                var LotIdsStr = (string)x["lot_ids_str"];
                var qDomain2 = new List<object> { id } ;

                var qFields2 = new List<string> { "pack_operation_ids" };
                
                var resp2 = await _amesSyncService.CallRead("stock.picking", qDomain2, qFields2, qPage);  //通过id，再调用CallRead方法获取pack_operation_ids

                if (resp2.ContainsKey("error"))
                {
                    var message = $"【拉取单据】{resp2["error"].ToString()}";
                    throw new AppException(message);
                }
                var res2 = (JArray)resp2["result"];

                if (res2 == null || res2.Count <= 0)
                {
                    return null;
                }
                
                var x2 = (JObject)res2[0];
                var id2_list = (JArray)x2["pack_operation_ids"];
                for (var j = 0; j < id2_list.Count; j++)
                {
                    var id2 = (int)id2_list[j];
                    var qDomain3 = new List<object> { id2 };

                    var qFields3 = new List<string> { "product_id", "product_uom_id", "lot_id", "create_date", "product_qty", };

                    var resp3 = await _amesSyncService.CallRead("stock.pack.operation", qDomain3, qFields3, qPage);  //通过id，再调用CallRead方法获取具体信息
                    var res3 = (JArray)resp3["result"];
                    var x3 = (JObject)res3[0];
                    var ProductId = (string)x3["product_id"][1];
                    if (!string.IsNullOrEmpty(ProductId) &&
                    (ProductId.Contains("Pr-Nd") || ProductId.Contains("Dy-Fe") || ProductId.Contains("Tb")) &&
                    !(ProductId.Length >= 2 && ProductId.Substring(ProductId.Length - 2) == "R0"))
                    {
                        ProductId += "R0";  //后加的R0没有批号
                    }

                    var LotId = (string)x3["lot_id"][1];
                    if (ProductId.Contains("R0"))  //产品代码最后两位带RO，不取其出库批次/序列号
                    {
                        LotId = "";
                    }
                    r.Add(new Recycled_Material_Ingredient_Record
                    {
                        AllyTopId = AllyTopId,   //合金名称，由多个产品组成为合金
                        LotIdsStr = LotIdsStr,   //产出批次信息（即这批出库产品用在了哪些生产工单中）
                        ProductId = ProductId,   //产品名称
                        ProductUomId = (string)x3["product_uom_id"][1],  // 单位
                        LotId = LotId,  // 出库批次/序列号
                        CreateDate = (string)x3["create_date"],
                        ProductQty = (decimal)x3["product_qty"],
                    });
                }

            }
            await Db.DoDeleteAsync<Recycled_Material_Ingredient_Record>(x => x.IsValid >= 0, true);
            await Db.DoInsertAsync<Recycled_Material_Ingredient_Record>(r);
            return r;
        }

        public async Task<List<Recycled_Material_Input_Info>> GetInputInfo()
        {
            //获取 仓库-作业-原料库-采购入库 入库的回收料的批号-产品-数量
            var qDomain = new List<object>
            {
                "&", // AND 条件
                new List<object> { "state", "=", "done" },
                new List<object> { "picking_type_id", "=", 126 },  // 拣货类型：原料库 领料出库
                new List<object> { "product_id", "ilike", "镨钕R0" },
            };

            var qFields = new List<string> { "id", "supplier_id" };
            var qPage = new
            {
                limit = 10000,
                offset = 0,
                context = new { lang = "zh_CN", tz = "Asia/Shanghai" },
            };
            var resp = await _amesSyncService.CallSearchRead("stock.picking", qDomain, qFields, qPage);  //获取全部符合合金号和日期的信息

            if (resp.ContainsKey("error"))
            {
                var message = $"【拉取单据】{resp["error"].ToString()}";
                throw new AppException(message);
            }
            var res = (JArray)resp["result"];

            if (res == null || res.Count <= 0)
            {
                return null;
            }
            var inputAll = new List<Recycled_Material_Input_Info>();

            for (var i = 0; i < res.Count; i++)
            {
                var x = (JObject)res[i];
                var id = (int)x["id"];
                var qDomain2 = new List<object> { id };

                var qFields2 = new List<string> { "pack_operation_ids" };

                var resp2 = await _amesSyncService.CallRead("stock.picking", qDomain2, qFields2, qPage);  //通过id，再调用CallRead方法获取pack_operation_ids

                if (resp2.ContainsKey("error"))
                {
                    var message = $"【拉取单据】{resp2["error"].ToString()}";
                    throw new AppException(message);
                }
                var res2 = (JArray)resp2["result"];

                if (res2 == null || res2.Count <= 0)
                {
                    return null;
                }

                var x2 = (JObject)res2[0];
                var id2_list = (JArray)x2["pack_operation_ids"];
                for (var j = 0; j < id2_list.Count; j++)
                {
                    var id2 = (int)id2_list[j];
                    var qDomain3 = new List<object> { id2 };

                    var qFields3 = new List<string> { "product_id", "product_uom_id", "lot_id", "create_date", "product_qty", };

                    var resp3 = await _amesSyncService.CallRead("stock.pack.operation", qDomain3, qFields3, qPage);  //通过id，再调用CallRead方法获取具体信息
                    var res3 = (JArray)resp3["result"];
                    var x3 = (JObject)res3[0];
                    inputAll.Add(new Recycled_Material_Input_Info
                    {
                        ProductId = (string)x3["product_id"][1],
                        ProductUomId = (string)x3["product_uom_id"][1],
                        LotId = (string)x3["lot_id"][1],
                        CreateDate = (string)x3["create_date"],
                        ProductQty = (decimal)x3["product_qty"],
                    });
                }
                

            }

            //获取 库存查看-原料库 中的批次-数量-产品
            var qDomain4 = new List<object>
            {
                new List<object> { "location_id", "child_of", 1481 }
            };

            var qFields4 = new List<string> { "id", "lot_id", "product_id", "weight"};

            var resp4 = await _amesSyncService.CallSearchRead("stock.quant", qDomain4, qFields4, qPage);  //获取全部符合合金号和日期的信息

            if (resp4.ContainsKey("error"))
            {
                var message = $"【拉取单据】{resp4["error"].ToString()}";
                throw new AppException(message);
            }
            var res4 = (JArray)resp4["result"];

            if (res4 == null || res4.Count <= 0)
            {
                return null;
            }
            var inventoryMaterial = new List<Recycled_Material_Ingredient_Record>();

            for (int i = 0; i < res4.Count; i++)
            {
                var x4 = (JObject)res4[i];
                inventoryMaterial.Add(new Recycled_Material_Ingredient_Record
                {
                    ProductId = (string)x4["product_id"][1],
                    LotId = (string)x4["lot_id"][1],
                    ProductQty = (decimal)x4["weight"],
                });
            }

            // 遍历在库数组中的每条信息
            // 先判断集合是否为空，避免空引用异常
            if (inventoryMaterial != null && inputAll != null)
            {
                // 外层循环：遍历inventoryMaterial
                for (int i = 0; i < inventoryMaterial.Count; i++)
                {
                    // 检查当前索引是否有效（防止集合在循环中被修改导致的异常）
                    if (i >= inventoryMaterial.Count)
                        break;

                    var inventory = inventoryMaterial[i];
                    if (inventory == null)
                        continue; // 跳过空对象

                    // 内层循环：遍历inputAll查找匹配项
                    for (int j = 0; j < inputAll.Count; j++)
                    {
                        // 检查当前索引是否有效
                        if (j >= inputAll.Count)
                            break;

                        var input = inputAll[j];
                        if (input == null)
                            continue; // 跳过空对象
                        string inputNumber = GetNumberPart(input.ProductId);
                        string inventoryNumber = GetNumberPart(inventory.ProductId);
                        // 匹配产品代码和批号
                        if (inputNumber == inventoryNumber && input.LotId == inventory.LotId)
                        {
                            Console.WriteLine("找到一处需要减去数量的内容");

                            // 打印减数量之前的信息
                            Console.WriteLine($"减数量前 - 入库批次 {input.LotId} 数量: {input.ProductQty}, 在库数量: {inventory.ProductQty}");

                            // 执行减法操作
                            input.ProductQty -= inventory.ProductQty;

                            // 打印减数量之后的信息
                            Console.WriteLine($"减数量后 - 入库批次 {input.LotId} 剩余数量: {input.ProductQty}");
                            Console.WriteLine("----------------------------------------");

                            break; // 找到后跳出内层循环，提高效率
                        }
                    }
                }
            }

            //需要排除库存中未出库的数量和批次，减去对应的数量
            //await Db.DoInsertAsync<Recycled_Material_Ingredient_Record>(r);
            await Db.DoDeleteAsync<Recycled_Material_Input_Info>(x => x.IsValid >= 0, true);
            await Db.DoInsertAsync<Recycled_Material_Input_Info>(inputAll);
            return inputAll;
        }
        //获取产品代码中的NC编码，进行对比
        private static string GetNumberPart(string productId)
        {
            if (string.IsNullOrEmpty(productId))
                return string.Empty;

            int startIndex = productId.IndexOf('[');
            int endIndex = productId.IndexOf(']');

            // 检查是否包含有效的[]格式
            if (startIndex >= 0 && endIndex > startIndex)
            {
                return productId.Substring(startIndex + 1, endIndex - startIndex - 1);
            }

            // 如果没有[]格式，返回原始字符串
            return productId;
        }

        public async Task FillOutputLotIdAsync()
        {
            var manager = new InventoryProcessor();
            var inputInfo = await Db.Set<Recycled_Material_Input_Info>().ToListAsync();
            var outputInfo = await Db.Set<Recycled_Material_Ingredient_Record>().ToListAsync();

            // 执行FIFO批次分配逻辑
            manager.ProcessInventory(inputInfo, outputInfo);

            await Db.DoDeleteAsync<Recycled_Material_Ingredient_Record>(x => x.IsValid >= 0, true);
            await Db.DoInsertAsync<Recycled_Material_Ingredient_Record>(outputInfo);
        }


    }
    public class InventoryProcessor
    {
        /// <summary>
        /// 处理出库信息，按日期排序并分配入库批次（仅通过[]后内容包含关系匹配）
        /// </summary>
        public void ProcessInventory(List<Recycled_Material_Input_Info> inputAll, List<Recycled_Material_Ingredient_Record> outputAll)
        {
            // 1. 处理出库信息：按创建日期升序排序（最早的先处理）
            var sortedOutputs = outputAll
                .Where(o => string.IsNullOrEmpty(o.LotId)) // 跳过已有LotId的出库项
                .OrderBy(o => o.CreateDate)
                .ToList();

            foreach (var outputItem in sortedOutputs)
            {
                // 提取出库产品的后缀内容（忽略[]中的核心编号）
                string outputCode = GetCodeWithoutLastDigit(outputItem.ProductId);
                decimal remainingQty = (decimal)outputItem.ProductQty;
                List<string> assignedLots = new List<string>();

                // 2. 查找匹配的入库信息：入库后缀包含出库后缀，按创建日期升序排序
                var availableInputs = inputAll
                    .Where(i =>
                    {
                        string inputCode = GetCodeWithoutLastDigit(i.ProductId);
                        // 比较排除最后一位后的数字编码
                        return inputCode == outputCode;
                    })
                    .Where(i => i.ProductQty > 0)
                    .OrderBy(i => i.CreateDate)
                    .ToList();

                // 从最早的入库批次开始扣减
                foreach (var inputItem in availableInputs)
                {
                    if (remainingQty <= 0) break;

                    // 计算可扣减数量
                    decimal deductQty = Math.Min((decimal)remainingQty, (decimal)inputItem.ProductQty);

                    // 扣减入库数量
                    Console.WriteLine($"扣减前 - 入库批次 {inputItem.LotId}: {inputItem.ProductQty}");
                    inputItem.ProductQty -= deductQty;
                    Console.WriteLine($"扣减后 - 入库批次 {inputItem.LotId}: {inputItem.ProductQty}");

                    // 记录分配的批次
                    assignedLots.Add($"{inputItem.LotId}({deductQty})");
                    remainingQty -= deductQty;
                }

                // 无论是否完全满足，都记录已分配的批次
                outputItem.LotId = string.Join(",", assignedLots);

                // 记录处理结果
                if (remainingQty > 0)
                {
                    Console.WriteLine($"警告: 产品 {outputItem.ProductId} 库存不足，未满足数量: {remainingQty}");
                }
                else
                {
                    Console.WriteLine($"产品 {outputItem.ProductId} 已完全分配，批次: {outputItem.LotId}");
                }
            }
        }

        /// <summary>
        /// 提取产品编码[]中的数字部分，并排除最后一位
        /// </summary>
        private string GetCodeWithoutLastDigit(string productId)
        {
            if (string.IsNullOrEmpty(productId))
                return string.Empty;

            // 使用正则表达式提取[]中的数字部分
            var match = Regex.Match(productId, @"\[(\d+)\]");
            if (!match.Success)
                return string.Empty;

            string numberPart = match.Groups[1].Value;

            // 排除最后一位（如果数字长度小于等于1，则返回空）
            if (numberPart.Length <= 1)
                return string.Empty;

            return numberPart.Substring(0, numberPart.Length - 1);
        }
    }
}
